type Decorator
    &(Component) => Component;

export function with:
    &(Component, Decorator) => Component
    &(cpt, f) => { f(cpt) };

export function with:
    &(Component, List[Decorator]) => Component
    &(cpt, @f) => cpt.{apply-all @f.{Seq}};

export function with:[T]
    &((&(T) => Component), Decorator) => (&(T) => Component)
    &(ctor, f) => (&(arg) => { f { ctor(arg) } });

export function with:[T]
    &((&(T) => Component), List[Decorator]) => (&(T) => Component)
    &(ctor, @f) => (&(arg) => {ctor(arg)}.{apply-all @f.{Seq}});


function Attr:
    &(String,String) => Decorator
    &(name,value) => &(cpt) => { Component (cpt map |.{ with
        { vdom::Attrs [(name,value)] }
    }|) };

function Attr:
    &(String,Computed[Bool]) => Decorator
    &(name,signal) => &(cpt) =>
        { Component
            \ map
            let (node,attach) := (cpt,signal),
            if attach:
                (node with { vdom::Attrs [(name,name)] }),
            else:
                node
        };

function Attr:
    &(String,Computed[String]) => Decorator
    &(name,values) => &(cpt) =>
        { Component
            \ map
            let (node,value) := (cpt,values),
            (node with { vdom::Attrs [(name,value)] })
        };

export function Event:
    &(String,EventCallback) => Decorator
    &(name,cb) => &(@node) =>
        \ do
        let id := PUID,
        let id := id.{String},
        let name := { "?.id?" (name,id) },
        \ do
        let handler := cb.EventHandler,
        { Component
            \ map let node := @node,
            (node with { vdom::Events [(name,handler)] })
        };

export function EventNoop:
    &(String) => Decorator
    &(name) => { Event (name, { EventCallback Noop }) };

export function RenderCond:
    &(Computed[Bool]) => Decorator
    &(@render) => &(cpt) =>
        { Component
            \ switch-map let render := @render,
            if render:
                cpt,
            else:
                Empty
        };

export function ShowCond:
    &(Computed[Bool]) => Decorator
    &(@show) => &(@node) =>
        { Component
            \ map
            let (node, show) := (@node, @show),
            if show:
                node,
            else:
                (node with { vdom::Styles [('display','none')] })
        };

export function EnableCond:
    &(Computed[Bool]) => Decorator
    &(@enabled) => &(@node) =>
        { Component
            \ map
            let (enabled, node) := (@enabled, @node),
            if enabled:
                node,
            else:
                (node with { vdom::Attrs [('disabled', 'disabled')] })
        };

export function DisableCond:
    &(Computed[Bool]) => Decorator
    &(@disabled) => { EnableCond (@disabled map |.{not}|) };

export function Style:
    &(ClassList) => Decorator
    &(class-list) => &(@node) =>
        if class-list.empty:
            @node,
        else:
            let class := (class-list join ' '),
            { Component (@node map
                |.{ with { vdom::Attrs [('class',class)] } }|
            ) };

export function DynamicStyle:
    &(Computed[ClassList]) => Decorator
    &(@class-list) => &(@node) =>
        { Component
            \ map
            let (class-list, node) := (@class-list, @node),
            let class := (class-list join ' '),
            (node with { vdom::Attrs [('class',class)] })
        };

export function InlineStyle:
    &(List[(String,String)]) => Decorator
    &(rules) => &(@node) =>
        { Component
            \ map let node := @node,
            (node with { vdom::Styles rules })
        };

export function DynamicInlineStyle:
    &(Computed[List[(String,String)]]) => Decorator
    &(@rules) => &(@node) =>
        { Component
            \ map
            let (rules, node) := (@rules, @node),
            (node with { vdom::Styles rules })
        };

export function Tooltip:
    &(String) => Decorator
    &(tooltip) => &(@node) =>
        { Component
            \ map let node := @node,
            (node with { vdom::Attrs [('title',tooltip)] })
        };

export const Focusable:
    Decorator
    &(@node) =>
        { Component
            \ map let node := @node,
            (node with { vdom::Attrs [('tabindex','0')] })
        };

export const Autofocus:
    Decorator
    &(@node) =>
        { Component
            \ map let node := @node,
            (node with { vdom::Attrs [('webuiAutofocus','webuiAutofocus')] })
        };
